#include <stdio.h>
#include <stdlib.h>
#include "main.h"
#include "state.h"
#include "stack.h"

#define NULL_ELEMENT (Element *)0

/* aktuální poslední prvek */
Element *lastElement = NULL_ELEMENT;
/* aktuální první prvek */
Element *firstElement = NULL_ELEMENT;

/* aktuální velikost stacku */
int size = 0;

/*
 * Metoda provede na stacku operaci "pop" - tj. vezme horní prvek, ze stacku
 * ho odstraní a vrátí na něj odkaz.
 */
State *stackPop(void){
	/* pop na prázdný stack je ne-e --> vrátíme null pointer */
	if(size <= 0){
		return (State *)0;
	}

	State *s = lastElement->value;

	Element *previous = lastElement->previous;
	free(lastElement);
	lastElement = previous;
	if(lastElement != NULL_ELEMENT){
		lastElement->next = NULL_ELEMENT;
	}
	size--;

	return s;
}

/*
 * Metoda provede na stacku operaci "push" - tj uloží zadaný prvek nahoru na
 * konec stacku.
 */
void stackPush(State *state){
	Element *elem = (Element *)malloc(sizeof(Element));
	if(elem == NULL){
		printf("Out of memory during push!");
		exit(EXIT_FAILURE);
	}
	/* nastavíme pro poslední element další element */
	if(size > 0){
		lastElement->next = elem;
		elem->previous = lastElement;
	}
	/* nebo pokud je stack prázdný, nastavíme jej jako dno stacku */
	else{
		firstElement = elem;
		elem->previous = NULL_ELEMENT;
	}
	/* nyní jsme vrchol stacku my, nad námi už nikdo není */
	elem->next = NULL_ELEMENT;
	/* nastavíme hodnotu = stav */
	elem->value = state;

	/* vrchol stacku posuneme */
	lastElement = elem;
	/* a stack zvětšíme */
	size++;
}

/*
 * Vrátí aktuální velikost stacku.
 */
int stackSize(void){
	return size;
}
